package com.example.base.tools.upgrade

import okhttp3.MediaType
import okhttp3.ResponseBody
import okio.Buffer
import okio.BufferedSource
import okio.ForwardingSource
import okio.buffer

/**
 * 自定义下载文件响应内容 ResponseBody, 用于替换 OkHttp 原本的 ResponseBody 来达到下载进度监听的效果
 * @param originalResponse 原本需要被替换的 ResponseBody
 * @param startPoint 断点续传的开始点
 * @param progressListener 文件下载进度监听回调
 */
class DownloadResponseBody(
    private val originalResponse: ResponseBody?,
    private val startPoint: Long = 0,
    private val progressListener: (
        /**  当前的下载进度, 按 1024 的百分比  **/
        progress: Int
    ) -> Unit,
    private val onErrorListener: (msg: String) -> Unit
) : ResponseBody() {

    override fun contentLength(): Long = originalResponse?.contentLength() ?: 0

    override fun contentType(): MediaType? = originalResponse?.contentType()

    override fun source(): BufferedSource {
        return DownloadSource().buffer()
    }

    // Custom download listener
    private inner class DownloadSource : ForwardingSource(originalResponse?.source() ?: Buffer()) {

        /**  总共读取的字节数  **/
        private var totalRead: Long = 0

        /**  上一次的进度百分比  **/
        private var lastPercentageOfProgress = -1

        override fun read(sink: Buffer, byteCount: Long): Long {
            var bytes: Long = 0
            try {
                bytes = super.read(sink, byteCount)
                totalRead += if (bytes == (-1).toLong()) 0 else bytes

                // 当前进度的百分比 = (当前读取字节数 + 开始偏移量) / 总字节数 * 100
                val percentageOfProgress =
                    ((totalRead.toDouble() + startPoint) / contentLength() * 100).toInt()
                if (percentageOfProgress != lastPercentageOfProgress) {
                    // callback progress
                    progressListener(percentageOfProgress)
                    lastPercentageOfProgress = percentageOfProgress
                }
            } catch (e: Exception) {
                e.printStackTrace()
                onErrorListener(e.message ?: "")
            }
            return bytes
        }
    }

}